import React, {PureComponent, Component} from 'react';
import styles from './imgCropper.less';
// props
// 最小图片尺寸 长宽  minImageWidth minImageHeight  (munber)
// 压缩后大小限制 imageSize 单位 M
// 容器大小 warpWidth warpHeight  do more
// 是否比例缩放  比例  长／宽  aspectRatio (number)  or

// this.imgCropper.save(src, imgSize);   imgSize (KB)
const loadImage = (url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'Anonymous'
    img.onload = () => resolve(img);
    img.onerror = err => reject(err);
    img.src = url;
  });
};

const handledataURLtoBlob = (dataurl) => {
  var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while(n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], {
    type: mime
  });
}

/**
 * 二进制 转 KB
 * 1B=8b, 1KB=1024B, 1024KB
 */
const bitToKB = (bit) => {
  let KB = 0;
  KB = Math.ceil(bit / 8 / 1024).toFixed(2);
  return KB
}

const imgCropperData = {
  minBoxH: 120,
  minBoxW: 160,
}


export default class ImgCropper extends PureComponent {
  state = {
    boxRatio: 0, // 长宽比
    width: 0, // 图片大小
    height: 0,
    boxH: 0, // 剪裁区域
    boxW: 0,
    minBoxH: 0, // 最小剪裁
    minBoxW: 0,
    ratio: 1, // 比例
    warp: 300, // 容器
    translate: '', // X or Y
    actionCmd: '', // mouse 指令
    clientY: 0, // 初始位置
    clientX: 0,
    sTop: 0, // 偏移量
    sLeft: 0,
  };
  _init = (src) => {
    let { minImageWidth, minImageHeight, imageSize } = this.props
    loadImage(src).then((img) => {
      const { width, height } = img,
        { warp, boxH, boxW, boxRatio, minBoxW, minBoxH } = this.state,
        ratio = warp / (width > height ? width : height); // 容器／图片  缩放比例
      let tempH = 0;
      let tempW= 0;
      if(minImageHeight) {
        tempH = minImageHeight * ratio;
        this.setState({minBoxH: minImageHeight * ratio})
      }
      if(minImageWidth) {
        tempW = minImageWidth * ratio;
        this.setState({minBoxW: minImageWidth * ratio})
      }
      if(minImageWidth && minImageHeight) {
        this.setState({boxRatio: minImageWidth/minImageHeight})
      }
      this.setState({ ratio,
        translate: width >= height ? 'Y' : 'X',
        boxW: tempW  || width * ratio / 2,
        boxH: tempH || height * ratio / 2,
        width: width * ratio,
        height: height * ratio,
        sLeft: 0,
        sTop: 0,
      });
    }).catch((err) => {
      console.log('err: ', err);
    });
  }
  ImgDragStart = (ev) => {

  }
  /**
   * @param {src} 图片src
   */
  save = async (src, imageSize) => {
    let saveCanvas = this.imgCanvas;
    let ctx = saveCanvas.getContext('2d');
    let {boxH, boxW} = this.state; // 剪裁尺寸
    let dataURL = '';
    ctx.clearRect(0, 0, saveCanvas.width, saveCanvas.height );
    const img = await loadImage(src);
    let {ratio, sLeft, sTop} = this.state // 放大缩小比例
    let dx = sLeft / ratio;
    let dy = sTop / ratio;
    let dw = boxW / ratio;
    let dh = boxH / ratio;
    saveCanvas.width = dw;
    saveCanvas.height = dh;
    ctx.drawImage(img, dx, dy, dw, dh, 0, 0, dw, dh);
    dataURL = saveCanvas.toDataURL();
    if(imageSize) {
      let size = bitToKB(handledataURLtoBlob(dataURL).size);
      let minify = 1;
      if(size > imageSize) {
        minify = Math.ceil(size / imageSize).toFixed(2);
      }
      dataURL = saveCanvas.toDataURL("image/jpeg");
    }
    return dataURL;
  }
  handleMouseDown = (oEvent, actionCmd) => {
    oEvent.stopPropagation()
    let { clientX, clientY } = oEvent;
    this.setState({ clientX, clientY, actionCmd })
  }

  componentWillMount() {
    if(this.props.src && this.props.visible) {
      this._init(this.props.src);
      this.mountAction();
    }
  }

  componentWillReceiveProps(nextProps) {
    this.setState({flag: nextProps.flag})
    let {src, visible} = nextProps
    if (!this.props.visible && nextProps.visible) {
      if(nextProps.src) {
        this._init(nextProps.src);
        this.mountAction();
      }
    } else if (this.props.visible && !nextProps.visible) {
      document.onmousemove = null;
      document.onmouseup = null;
    }
  }

  mountAction = () => {
    document.selectNodeContents = () => {

    }
    document.onmouseup = () => {
      if (this.state.actionCmd) {
        this.setState({actionCmd: ''})
      }
    }
    document.onmousemove = (oEvent) => {
      let {actionCmd, canDeform, width, height, sLeft, sTop, boxH, boxW, clientX, clientY} = this.state,
        oX = oEvent.clientX,
        oY = oEvent.clientY;
      switch(actionCmd) {
        case 'drag':
          let drapLeft = oX - clientX + sLeft < 0 ? 0 : oX - clientX + sLeft;
          let dragTop = oY - clientY + sTop < 0 ? 0 : oY - clientY + sTop;
          if(boxW + drapLeft > width) {
            drapLeft = width - boxW
          }
          if(boxH + dragTop > height) {
            dragTop = height - boxH
          }
          this.setState({sLeft: drapLeft, sTop: dragTop, clientX: oX, clientY: oY });
          break;
        case 'sclae':
          let { minBoxH, minBoxW, boxRatio } = this.state;
          let w = oX - clientX + boxW;
          let h = oY - clientY + boxH;
          if(w + sLeft > width) { // 最宽
            w = width - sLeft
          }
          if(h + sTop > height) { // 最高
            h = height - sTop
          }
          if(minBoxH) { // 最小 高
            h = h <= minBoxH ? minBoxH : h
          }
          if(minBoxW) { // 最小 宽
            w = w <= minBoxW ? minBoxW : w
          }
          if(boxRatio) { // 长宽比 w/h
            if(w >= h) {
              h = (w / boxRatio + sTop) > height ? height - sTop : w / boxRatio;
              w = h * boxRatio;
            } else {
              w = (h * boxRatio + sLeft) > width ? width - sLeft : h * boxRatio;
              h = w / boxRatio;
            }
          }
          this.setState({boxH: h, boxW: w, clientX: oX, clientY: oY})
          break;
      }
    }
  }
  render() {
    const {src} = this.props,
          { ratio, width, height, warp, translate, canMove, sTop, sLeft, boxH, boxW, boxRatio } = this.state,
          isWidth = width === warp ? true : false,
          slate = isWidth ? warp - height : warp - width;
    let realImageWidth = (boxW / ratio) > 0 ? (boxW / ratio).toFixed() : 0;
    let realImageHeight = (boxW / ratio) > 0 ? (boxH / ratio).toFixed() : 0;
    return (
      <div className={styles['image-cropper']}>
        <div className={styles['cropper-wrap']}>
          <div className={styles['cropper-bg']}>
            <img src={src} style={{ height, width }}/>
            <div className={styles['cropper-canvas']}
              style={{ width, height, transform: `translate${translate}(${slate / 2}px)` }}
            >
              <div className={styles['crop-view-box']} style={{position: 'relative'}}>
                <div className={styles['cropper-crop-box']}
                  ref={(cropBox) => { this.cropBox = cropBox }}
                  onMouseDown={(ev) => this.handleMouseDown(ev, 'drag')}
                  style={{
                    width: boxW, height: boxH,
                    transform: `translateX(${sLeft}px) translateY(${sTop}px)`
                  }}
                >
                  <img src={src} style={{ height, width, userSelect: 'none',
                    transform: `translateX(-${sLeft}px) translateY(-${sTop}px)` }}
                    onMouseDown = {(ev) => {ev.preventDefault()}} />
                  <span ref={(ponit) => { this.point = ponit }}
                    className={styles['cropper-point']}
                    onMouseDown={(ev)=> this.handleMouseDown(ev, 'sclae')}
                  >
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
        {/* <div className={styles['preview-layout']}> */}
        <p className={styles['size-tips']}>{realImageWidth} * {realImageHeight}</p>
          <div className={styles['cropper-preview']} style={{width: boxW, height: boxH ,transform: `translate${translate}(${slate / 2}px)`}}>
            <img src={src}
              className={styles['cropper-preview-img']}
              style={{ width, height,
                transform: `translateX(-${sLeft}px) translateY(-${sTop}px)` }}
            />
          </div>
          <canvas ref={(canvas) => {this.imgCanvas = canvas}} crossOrigin="anonymous"
            style={{display: 'none'}}
          >
          </canvas>
        {/* </div> */}
      </div>
    )
  }
}
